/*
 * $Id: TcpServer.h,v 1.10 2006-04-16 04:46:55 bacon Exp $
 */

#ifndef _XPP_NET_TCPSERVER_CLASS_
#define _XPP_NET_TCPSERVER_CLASS_

#include <xpp/net/TcpSocket.h>
#include <xpp/net/TcpAddress.h>
#include <xpp/bas/Thread.h>
#include <xpp/bas/LinkedList.h>
#include <xpp/Uncopyable.h>
#include <xp/bas/assert.h>

namespace xpp
{
	namespace net
	{

		class TcpServer: public Uncopyable 
		{
		public:
			TcpServer ();
			TcpServer (const TcpAddress& address);
			virtual ~TcpServer ();
		
			enum {
				ERR_NONE      = 0,
				ERR_OPEN      = 1,
				ERR_BIND      = 2,
				ERR_LISTEN    = 3,
				ERR_EXCEPTION = 4
			};
		
			virtual int start (int* err_code = XP_NULL);
			virtual int stop ();

			bool isServing () const 
			{ 
				return server_serving; 
			}

			bool isStopRequested () const 
			{
				return stop_requested;
			}
			void setStopRequested (bool req)
			{
				stop_requested = req;
			}

			const TcpAddress& bindingAddress () const
			{
				return binding_address;
			}
			void setBindingAddress (const TcpAddress& address)
			{
				xp_assert (server_serving == false);
				binding_address = address;
			}

			xp_size_t maxConnections () const 
			{
				return max_connections;
			}
			void setMaxConnections (xp_size_t mc) 
			{
				// don't disconnect client connections 
				// establised before maxConn is set.
				// 0 means there's no restriction over 
				// the number of connection.
				max_connections = mc;
			}

			xp_size_t clientCount () const 
			{ 
				return client_list.size(); 
			}
			xp_size_t connectionCount () const
			{
				return client_list.size(); 
			}
		
		protected:
			class Client: public xpp::bas::Thread 
			{
			public:
				friend class TcpServer;
		
				Client (TcpServer* server);

				int run ();
				int stop ();
		
			private:
				TcpServer* server;
				TcpSocket  socket;
				TcpAddress address;
			};
			
			TcpAddress binding_address;
			bool        stop_requested;
			bool        server_serving;
			xp_size_t   max_connections;
		
			typedef xpp::bas::LinkedList<Client*> ClientList;
			ClientList client_list;
		
			friend class TcpServer::Client;
			virtual int handle_client (
				TcpSocket* sock, TcpAddress* addr) = 0;
		
		private:
			void delete_dead_clients ();
			void delete_all_clients  ();
		};
	
	}
}
		
#endif
		
